#include "assert.h"
#include "datasturcture.h"
#include "proc.h"
#include "stddef.h"

#include "lock/wait.h"



void
wait_init(wait_t* wait, proc_t* proc) {
    wait->proc = proc;
    wait->wakeupFlags = WT_INTERRUPTED;
    list_init(&(wait->waitLink));
}

void
waitQueue_init(waitQueue_t* q) {
    list_init(&(q->wait_head));
}

void
waitQueue_add(waitQueue_t* q, wait_t* wait) {
    assert(list_empty(&(wait->waitLink)) && wait->proc != NULL);
    wait->waitQueue = q;
    list_add_before(&(q->wait_head), &(wait->waitLink));
}

void
waitQueue_del(waitQueue_t* q, wait_t* wait) {
    assert(!list_empty(&(wait->waitLink)) && wait->waitQueue == q);
    list_delInit(&(wait->waitLink));
}

wait_t*
waitQueue_next(waitQueue_t* q, wait_t* wait) {
    assert(!list_empty(&(wait->waitLink)) && wait->waitQueue == q);
    list_entry_t* le = list_next(&(wait->waitLink));
    if (le != &(q->wait_head))
        return le2wait(le, waitLink);
    return NULL;
}

wait_t*
waitQueue_prev(waitQueue_t* q, wait_t* wait) {
    assert(!list_empty(&(wait->waitLink)) && wait->waitQueue == q);
    list_entry_t* le = list_prev(&(wait->waitLink));
    if (le != &(q->wait_head))
        return le2wait(le, waitLink);
    return NULL;
}

wait_t*
waitQueue_first(waitQueue_t* q) {
    list_entry_t* le = list_next(&(q->wait_head));
    if (le != &(q->wait_head))
        return le2wait(le, waitLink);
    return NULL;
}

wait_t*
waitQueue_last(waitQueue_t* q) {
    list_entry_t* le = list_prev(&(q->wait_head));
    if (le != &(q->wait_head))
        return le2wait(le, waitLink);
    return NULL;
}

bool
waitQueue_isEmpty(waitQueue_t* q) {
    return list_empty(&(q->wait_head));
}

bool
wait_isInQueue(wait_t* wait) {
    return !list_empty(&(wait->waitLink));
}

void
wakeup_wait(waitQueue_t* q, wait_t* wait, uint32_t wakeupFlags, bool del) {
    if (del)
        waitQueue_del(q, wait);
    wait->wakeupFlags = wakeupFlags;
    // proc_wakeup(wait->proc);
}

void
wakeup_first(waitQueue_t* q, uint32_t wakeupFlags, bool del) {
    wait_t* wait = waitQueue_first(q);
    if (wait != NULL)
        wakeup_wait(q, wait, wakeupFlags, del);
}

void
wakeup_queue(waitQueue_t* q, uint32_t wakeupFlags, bool del) {
    wait_t* wait = waitQueue_first(q);
    if (wait != NULL) {
        while (wait != NULL) {
            wakeup_wait(q, wait, wakeupFlags, del);
            if (del)
                wait = waitQueue_first(q);
            else
                wait = waitQueue_next(q, wait);
        }
    }
}

void
wait_current_set(waitQueue_t* q, wait_t* wait, uint32_t waitState) {
    assert(getCurrentProc() != NULL);
    wait_init(wait, getCurrentProc());
    getCurrentProc()->state = SLEEPING;
    getCurrentProc()->waitState = waitState;
    waitQueue_add(q, wait);
}